using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.IO;
using System.Windows.Forms;

using common = Microsoft.ConnectionEngine.Common;

namespace ServiceProviderRegisterInstaller
{
    [RunInstaller(true)]
    public partial class Installer : common.Install.Installer
    {
        #region Context Parameter constants
        #endregion

        #region Other constants
        const string PUBLIC_KEY_FILE_NAME = "PublicKey.xml";
        const string PRIVATE_KEY_FILE_NAME = "PrivateKey.xml";

        const string WEB_CONFIG_FILE_NAME = "Web.config";

        const string DEFAULT_WEB_SERVICE_APP_NAME = "ServiceProviderRegisterWS";

        const string DB_CREATE_FILE_NAME = "DB-Create.sql";
        const string DB_OBJECT_CREATE_FILE_NAME = "DB-CreateObjects.sql";
        const string DB_DATA_CREATE_FILE_NAME = "DB-CreateData.sql";
        const string DB_DESTROY_FILE_NAME = "DB-Destroy.sql";
        #endregion

        public Installer()
        {
            InitializeComponent();
        }

        public override void Install(IDictionary savedState)
        {
            FileInfo fileInfo;

            string serviceInstallFolder = Path.Combine(this.InstallFolder, "WebService");
            string serviceBinFolder = Path.Combine(serviceInstallFolder, "bin");
            string dbScriptFolder = Path.Combine(InstallFolder, "Database Scripts");

            #region Fix parameters
            FixParameters();

            string sprWSSite = this.Context.Parameters[SPR_WS_SITE];
            if (sprWSSite == null) sprWSSite = DEFAULT_WEB_SERVICE_APP_NAME;
            #endregion

            #region Create public and private keys
            common.Crypto.RSAKeyCreator kc = new Microsoft.ConnectionEngine.Common.Crypto.RSAKeyCreator();
            string publicKey = kc.PublicKeyXml;
            string privateKey = kc.PrivateKeyXml;

            fileInfo = new FileInfo(Path.Combine(serviceBinFolder, PUBLIC_KEY_FILE_NAME));
            SaveDataToFile(fileInfo.FullName, publicKey);

            fileInfo = new FileInfo(Path.Combine(serviceBinFolder, PRIVATE_KEY_FILE_NAME));
            SaveDataToFile(fileInfo.FullName, privateKey);
            #endregion

            #region Set config file parameters
            fileInfo = new FileInfo(Path.Combine(serviceInstallFolder, WEB_CONFIG_FILE_NAME));
            if (fileInfo.Exists)
            {
                Dictionary<string, string> parameters = new Dictionary<string, string>();

                parameters.Add("[installfolder]", InstallFolder);
                foreach (DictionaryEntry parameter in this.Context.Parameters)
                {
                    parameters.Add("[" + parameter.Key.ToString() + "]", parameter.Value.ToString());
                }

                SetFileParameters(fileInfo.FullName, parameters);
            }
            #endregion

            #region Create Web Service IIS Virtual Directory
            string appPoolName = this.Context.Parameters[APP_POOL_NAME];
            string appPoolUsername = this.Context.Parameters[APP_POOL_USER];
            string appPoolPassword = this.Context.Parameters[APP_POOL_PASS];

            CreateIISVirtualDir(GetCurrentHostName(), sprWSSite, serviceInstallFolder, appPoolName, appPoolUsername, appPoolPassword);
            #endregion

            #region Create and setup database
            string dbServer = this.Context.Parameters[SPR_DB_HOST];
            string dbName = this.Context.Parameters[SPR_DB_NAME];
            string dbUser = this.Context.Parameters[DB_ADMIN_USER];
            string dbPass = this.Context.Parameters[DB_ADMIN_PASS];

            fileInfo = new FileInfo(Path.Combine(dbScriptFolder, DB_CREATE_FILE_NAME));
            if (this.ExecuteSQLScript(dbServer, dbName, dbUser, dbPass, fileInfo.FullName))
            {
                fileInfo = new FileInfo(Path.Combine(dbScriptFolder, DB_OBJECT_CREATE_FILE_NAME));
                if (this.ExecuteSQLScript(dbServer, dbName, dbUser, dbPass, fileInfo.FullName))
                {
                    Dictionary<string, string> parameters = new Dictionary<string, string>();

                    parameters.Add("[sprhost]", GetCurrentHostName());
                    parameters.Add("[sprwssite]", sprWSSite);
                    parameters.Add("[sprpublickey]", publicKey.Replace("'", "''"));

                    fileInfo = new FileInfo(Path.Combine(dbScriptFolder, DB_DATA_CREATE_FILE_NAME));

                    this.ExecuteSQLScript(dbServer, dbName, dbUser, dbPass, fileInfo.FullName, parameters);
                }
            }
            #endregion

            savedState.Add(SPR_WS_SITE, sprWSSite);
            savedState.Add(APP_POOL_NAME, appPoolName);

            base.Install(savedState);
        }

        public override void Uninstall(IDictionary savedState)
        {
            FileInfo fileInfo;
            string serviceInstallFolder = Path.Combine(this.InstallFolder, "WebService");
            string serviceBinFolder = Path.Combine(serviceInstallFolder, "bin");

            #region Get saved state parameters
            string sprWSSite;
            string appPoolName;
            if (savedState.Count > 0)
            {
                sprWSSite = savedState[SPR_WS_SITE].ToString();
                appPoolName = savedState[APP_POOL_NAME].ToString();
            }
            else
            {
                sprWSSite = this.Context.Parameters[SPR_WS_SITE];
                if (sprWSSite == null) sprWSSite = DEFAULT_WEB_SERVICE_APP_NAME;

                appPoolName = this.Context.Parameters[APP_POOL_NAME];
                if (appPoolName == null) appPoolName = DEFAULT_APP_POOL_NAME;
            }
            #endregion

            ReStartIIS();

            #region Remove Web Service IIS Virtual Directory
            RemoveIISVirtualDir(GetCurrentHostName(), sprWSSite, appPoolName);
            #endregion

            #region Remove public and private keys
            fileInfo = new FileInfo(Path.Combine(serviceBinFolder, PUBLIC_KEY_FILE_NAME));
            if (fileInfo.Exists) fileInfo.Delete();

            fileInfo = new FileInfo(Path.Combine(serviceBinFolder, PRIVATE_KEY_FILE_NAME));
            if (fileInfo.Exists) fileInfo.Delete();
            #endregion

            base.Uninstall(savedState);
        }

        public override void Rollback(IDictionary savedState)
        {
            FileInfo fileInfo;
            string serviceInstallFolder = Path.Combine(this.InstallFolder, "WebService");
            string serviceBinFolder = Path.Combine(serviceInstallFolder, "bin");
            string dbScriptFolder = Path.Combine(InstallFolder, "Database Scripts");

            #region Fix parameters
            FixParameters();

            string sprWSSite = this.Context.Parameters[SPR_WS_SITE];
            if (sprWSSite == null) sprWSSite = DEFAULT_WEB_SERVICE_APP_NAME;
            #endregion

            #region Destroy database
            string dbServer = this.Context.Parameters[SPR_DB_HOST];
            string dbName = this.Context.Parameters[SPR_DB_NAME];
            string dbUser = this.Context.Parameters[DB_ADMIN_USER];
            string dbPass = this.Context.Parameters[DB_ADMIN_PASS];

            fileInfo = new FileInfo(Path.Combine(dbScriptFolder, DB_DESTROY_FILE_NAME));
            try
            {
                this.ExecuteSQLScript(dbServer, dbName, dbUser, dbPass, fileInfo.FullName);
            }
            catch
            {
            }
            #endregion

            #region Remove Web Service IIS Virtual Directory
            string appPoolName = this.Context.Parameters[APP_POOL_NAME];

            RemoveIISVirtualDir(GetCurrentHostName(), sprWSSite, appPoolName);
            #endregion

            #region Remove public and private keys
            fileInfo = new FileInfo(Path.Combine(serviceBinFolder, PUBLIC_KEY_FILE_NAME));
            if (fileInfo.Exists) fileInfo.Delete();

            fileInfo = new FileInfo(Path.Combine(serviceBinFolder, PRIVATE_KEY_FILE_NAME));
            if (fileInfo.Exists) fileInfo.Delete();
            #endregion

            if (savedState.Count > 0)
            {
                base.Rollback(savedState);
            }
        }

        #region Private methods
        private void ShowParameters()
        {
            MessageBox.Show(GetParamtersForDisplay(), "Setup Parameters");
        }

        private void ShowSavedState(IDictionary savedState)
        {
            string output = "";

            foreach (DictionaryEntry item in savedState)
            {
                if (output.Length > 0) output += "\n";
                output += "[" + item.Key.ToString() + "] = '" + item.Value.ToString() + "'";
            }

            MessageBox.Show(GetSavedStateForDisplay(savedState), "Setup Saved State");
        }
        #endregion
    }
}